"""
    textAnalysis是文本分析模块，对用户的回答进行打分、结合面试岗位以及预先设定的指标对用户的问题回答、个人简历信息进行专业能力评估
"""

import json
import ssl
import threading
from queue import Queue, Empty
from typing import Dict, Any, Optional, Union
from urllib.parse import urlencode, urlparse
from datetime import datetime
from wsgiref.handlers import format_date_time
from time import mktime
import websocket
import hmac
import hashlib
import base64
import os
import PyPDF2
import re # 确保已经导入 re 模块
from langchain.tools import tool

APP_ID="fc9821ef",
API_KEY="b07b7594a96a4f5886e24faae8c393ea",
API_SECRET="YWZlOTA3MGU2ZDMzYzhiMjllODRmYTNj"

class SparkFileProcessor:
    """讯飞星火文档评估处理器，支持处理文件路径或直接传入字符串。"""
    
    def __init__(
        self,
        appid: str = APP_ID,
        api_key: str = API_KEY,
        api_secret: str = API_SECRET,
        spark_url: str = "wss://spark-api.xf-yun.com/v4.0/chat",
        domain: str = "4.0Ultra",
        max_tokens: int = 4096,
        temperature: float = 0.1
    ):
        self.config = {
            "appid": "fc9821ef",
            "api_key":"b07b7594a96a4f5886e24faae8c393ea",
            "api_secret": "YWZlOTA3MGU2ZDMzYzhiMjllODRmYTNj",
            "spark_url": spark_url,
            "domain": domain,
            "max_tokens": max_tokens,
            "temperature": temperature
        }
        self.ws: Optional[websocket.WebSocketApp] = None
        self.response_queue = Queue()
        self.accumulated_content = ""
        self.ws_thread: Optional[threading.Thread] = None

    def _generate_auth_url(self) -> str:
        """生成认证URL"""
        now = datetime.now()
        date = format_date_time(mktime(now.timetuple()))
        parsed_url = urlparse(self.config['spark_url'])
        host = parsed_url.netloc
        path = parsed_url.path

        # 生成签名
        signature_origin = f"host: {host}\ndate: {date}\nGET {path} HTTP/1.1"
        signature_sha = hmac.new(
            self.config['api_secret'].encode(),
            signature_origin.encode(),
            hashlib.sha256
        ).digest()
        signature_b64 = base64.b64encode(signature_sha).decode()

        # 构造认证头
        auth_str = (
            f'api_key="{self.config["api_key"]}", '
            f'algorithm="hmac-sha256", '
            f'headers="host date request-line", '
            f'signature="{signature_b64}"'
        )
        auth_b64 = base64.b64encode(auth_str.encode()).decode()

        return f"{self.config['spark_url']}?{urlencode({'authorization': auth_b64, 'date': date, 'host': host})}"

    def _handle_websocket_events(self):
        """WebSocket事件处理"""
        def on_message(ws, message):
            try:
                data = json.loads(message)
                if data['header']['code'] != 0:
                    error = f"API错误[{data['header']['code']}]: {data['header'].get('message', '无详情')}"
                    self.response_queue.put((None, error))
                    ws.close()
                    return

                content = data["payload"]["choices"]["text"][0]["content"]
                self.accumulated_content += content
                
                if data["payload"]["choices"]["status"] == 2:
                    self.response_queue.put((self.accumulated_content, None))
                    ws.close()

            except Exception as e:
                self.response_queue.put((None, f"消息处理失败: {str(e)}"))
                ws.close()

        def on_error(ws, error):
            self.response_queue.put((None, f"连接错误: {str(error)}"))
            ws.close()

        def on_close(ws, *args):
            if not self.accumulated_content:
                self.response_queue.put((None, "连接意外中断"))

        return on_message, on_error, on_close

    def _call_api(self, query: str) -> Dict[str, Any]:
        """执行API调用"""
        self.accumulated_content = ""
        try:
            on_message, on_error, on_close = self._handle_websocket_events()
            
            self.ws = websocket.WebSocketApp(
                self._generate_auth_url(),
                on_open=lambda ws: self._send_request(ws, query),
                on_message=on_message,
                on_error=on_error,
                on_close=on_close
            )

            self.ws_thread = threading.Thread(
                target=self.ws.run_forever,
                kwargs={"sslopt": {"cert_reqs": ssl.CERT_NONE}},
                daemon=True
            )
            self.ws_thread.start()

            try:
                result, error = self.response_queue.get(timeout=120)
                return {"success": error is None, "data": result, "error": error}
            except Empty:
                return {"success": False, "error": "请求超时"}
            
        except Exception as e:
            return {"success": False, "error": str(e)}
        finally:
            if self.ws and self.ws.sock:
                self.ws.close()
            self.ws_thread = None

    def _send_request(self, ws, query: str):
        """发送请求"""
        try:
            payload = {
                "header": {"app_id": self.config['appid'], "uid": "doc_evaluator"},
                "parameter": {
                    "chat": {
                        "domain": self.config['domain'],
                        "temperature": self.config['temperature'],
                        "max_tokens": self.config['max_tokens']
                    }
                },
                "payload": {
                    "message": {
                        "text": [{"role": "user", "content": query}]
                    }
                }
            }
            ws.send(json.dumps(payload, ensure_ascii=False))
        except Exception as e:
            self.response_queue.put((None, f"请求发送失败: {str(e)}"))
            ws.close()

    def _get_content(self, input_data: Union[str, os.PathLike]) -> str:
        """根据输入类型获取文本内容：如果是文件路径则读取，否则直接返回字符串。"""
        if isinstance(input_data, (str, os.PathLike)) and os.path.exists(input_data):
            file_path = str(input_data)
            ext = os.path.splitext(file_path)[1].lower()
            if ext == '.txt':
                with open(file_path, 'r', encoding='utf-8') as f:
                    return f.read()
            elif ext == '.pdf':
                with open(file_path, 'rb') as f:
                    # PyPDF2 may return None for empty pages, so handle that with 'or ''
                    return '\n'.join(
                        page.extract_text() or '' 
                        for page in PyPDF2.PdfReader(f).pages
                    )
            else:
                raise ValueError("仅支持TXT/PDF文件路径")
        elif isinstance(input_data, str):
            return input_data
        else:
            raise TypeError("输入必须是文件路径（TXT/PDF）或字符串")

    def comprehensive_evaluate(self, input_data: Union[str, os.PathLike]) -> Dict[str, Any]:
        """
        综合评估（纯评语版）
        :param input_data: 要评估的文本内容字符串或文件路径（TXT/PDF）
        """
        try:
            content = self._get_content(input_data)
            query = (
                "根据文本内容，从大数据、人工智能、物联网三个领域中选择一个领域，"
                "如果是物联网则从用户需求洞察力，技术可行性分析，商业化能力，跨团队协作能力，市场敏感度，应变能力这些方面去用简要中文进行评估并且引用支撑材料，如果不涉及则不对对应方面做阐述"
                "如果是大数据领域则从数据架构设计能力，编程与算法能力，问题排查效率，技术文档能力，新技术学习能力，团队协作意识这些方面去用简要中文进行评估并且引用支撑材料，如果不涉及则不对对应方面做阐述"
                "如果是人工智能领域则从模型测试，数据质量分析，自动化测试开发、伦理安全、跨领域知识储备、应急响应能力这些方面去用中文进行评估并且引用支撑材料，如果不涉及则不对对应方面做阐述" 
                "结果以json的格式返回" 
                "例：{"
                "用户洞察力：较强的用户洞察力\n"
                "技术可行性分析：......\n}"
                f"\n文本内容：\n{content}"
            )
            response = self._call_api(query)
            
            if response["success"]:
                # 清洗结果并去除句号
                cleaned = response["data"].strip().replace("。", "")
                return {"success": True, "data": cleaned}
            return response
        except Exception as e:
            return {"success": False, "error": str(e)}

    def quantitative_score(self, input_data: Union[str, os.PathLike]) -> Dict[str, Any]:
        """
        生成量化评分（仅总分）
        :param input_data: 要评分的文本内容字符串或文件路径（TXT/PDF）
        """
        try:
            content = self._get_content(input_data)
            query = (
                "根据文本内容，从大数据、人工智能、物联网三个领域中选择一个领域，"
                "如果是物联网则从用户需求洞察力，技术可行性分析，商业化能力，跨团队协作能力，市场敏感度，应变能力这些方面去做一个评分，"
                "如果是大数据领域则从数据架构设计能力，编程与算法能力，问题排查效率，技术文档能力，新技术学习能力，团队协作意识这些方面去做一个评分，"
                "如果是人工智能领域则从模型测试，数据质量分析，自动化测试开发、伦理安全、跨领域知识储备、应急响应能力这些方面去做一个评分，"
                "请直接给出文档的百分制总分（0-100的整数），结果严格以json格式返回，键名为'score'。\n" \
                "例:{\"score\":90}\n"
                f"文本内容：\n{content}"
            )
            response = self._call_api(query)
        
            if response["success"]:
                response_data_str = response["data"]
                
                # 首先尝试从 Markdown 代码块中提取 JSON 字符串
                # 匹配 ```json\n{...}\n``` 模式
                json_match = re.search(r'```json\s*(\{.*\})\s*```', response_data_str, re.DOTALL)
                
                extracted_json_str = None
                if json_match:
                    extracted_json_str = json_match.group(1)
                else:
                    # 如果没有匹配到 Markdown 代码块，尝试直接使用原始字符串
                    # 这里可以添加一些日志，以便在没有匹配到代码块时也能知道
                    print(f"警告: 未在API响应中找到 ```json``` 代码块，尝试直接解析原始字符串。原始响应: '{response_data_str}'")
                    extracted_json_str = response_data_str

                # 确保提取到的数据是字符串类型且不为空
                if not isinstance(extracted_json_str, str) or not extracted_json_str.strip():
                    return {"success": False, "error": f"API返回的数据为空或不是有效的字符串格式。原始响应: '{response_data_str}'"}

                # --- 尝试 1: 解析为 JSON ---
                try:
                    parsed_data = json.loads(extracted_json_str)
                    score = parsed_data.get("score")
                    if score is not None:
                        return {
                            "success": True,
                            "data": int(score)
                        }
                    else:
                        return {"success": False, "error": f"从API响应的JSON中未找到 'score' 键。解析内容: '{extracted_json_str}'"}

                except json.JSONDecodeError as e:
                    # --- 尝试 2: 如果 JSON 解析失败，则尝试直接从字符串中提取数字 ---
                    # 即使没有找到 ```json``` 块，我们也可能得到一个简单的数字或 "score:数字" 格式
                    try:
                        # 尝试匹配 "score:数字" 格式
                        match = re.search(r'score:(\d+)', response_data_str) # 仍然从原始响应中查找
                        if match:
                            score_str = match.group(1)
                        else:
                            # 如果不是 "score:数字" 格式，尝试直接匹配字符串中的所有数字
                            match = re.search(r'(\d+)', response_data_str) # 仍然从原始响应中查找
                            if match:
                                score_str = match.group(1)
                            else:
                                # 如果没有找到任何数字
                                return {
                                    "success": False,
                                    "error": f"无法从API响应中找到有效的评分数字。原始响应: '{response_data_str}'"
                                }
                        
                        return {
                            "success": True,
                            "data": int(score_str)
                        }

                    except ValueError:
                        return {
                            "success": False,
                            "error": f"从API响应中提取的评分无法转换为整数。原始响应: '{response_data_str}'"
                        }
                    except Exception as e:
                        return {"success": False, "error": f"直接解析API响应失败: {str(e)}. 原始响应: '{response_data_str}'"}

            return response
        except Exception as e:
            return {"success": False, "error": str(e)}

# 工具函数组
@tool("document_evaluator", return_direct=True)
def evaluate_tool(input_data: Union[str, os.PathLike]) -> dict:
    """文档综合评估工具，输入为待评估的文本内容字符串或文件路径（TXT/PDF）。"""
    return SparkFileProcessor(
        appid="fc9821ef",
        api_key="b07b7594a96a4f5886e24faae8c393ea",
        api_secret="YWZlOTA3MGU2ZDMzYzhiMjllODRmYTNj"
    ).comprehensive_evaluate(input_data)

@tool("document_scorer", return_direct=True)
def score_tool(input_data: Union[str, os.PathLike]) -> dict:
    """文档量化评分工具，输入为待评分的文本内容字符串或文件路径（TXT/PDF）。"""
    return SparkFileProcessor(
        appid="fc9821ef",
        api_key="b07b7594a96a4f5886e24faae8c393ea",
        api_secret="YWZlOTA3MGU2ZDMzYzhiMjllODRmYTNj"
    ).quantitative_score(input_data)










if __name__ == "__main__":
    # 使用示例
    processor = SparkFileProcessor()
    
    # 示例文本内容
    sample_text_content = """
    然后在我研究生这两年期间主要参与并负责了个项目。
    第一个项目是工程机械智慧施工。在第一个项目中，
    我主要负责的工作可以分为三个部分。
    因为我们项目主要是为了实现一个推土机在整个矿区场景中自主作业的功能。
    因此，我首先是搭建了一个通讯系统，因为涉及到一些任务的下发和应答，
    包括传感器状态转发和传感及数据。
    """
    
    print("\n--- 评估直接字符串 ---")
    scoring_string = processor.quantitative_score(sample_text_content)
    # comprehensive=processor.comprehensive_evaluate(sample_text_content)
    # print("字符串量化评分结果：", comprehensive)
    print("字符串量化评分结果：", scoring_string)                         #不能同时调用两个
    
    # 初始化LangGraph代理 (这里假设您有一个有效的Anthropic模型配置)
    # 注意: 'anthropic:claude-3-7-sonnet-latest' 是一个示例模型名称，您需要根据实际情况替换为您可用的模型
    # 或者，如果您不使用LangGraph，可以删除此部分
    # agent = create_react_agent(
    #     model="anthropic:claude-3-7-sonnet-latest",
    #     tools=[evaluate_tool, score_tool],
    #     prompt="您是一个专业文档评估助手，可以使用以下工具："
    #            "1. document_evaluator - 综合质量评估\n"
    #            "2. document_scorer - 生成量化评分"
    # )